/*
 * @Author: your name
 * @Date: 2021-06-27 16:07:47
 * @LastEditTime: 2021-06-27 17:49:58
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 */

import { Vec2, Node, math, find, UITransform, Vec3, Canvas } from "cc";
import { TimerManager } from "../../frameworks/base/TimerManager";
import { UIRoot } from "./UIRoot";


export class CanvasCamera {
    private root!: Node;
    private _x: number = 0;
    private _y: number = 0;
    private scale: number = 1;
    private width: number = 0;
    private height: number = 0;
    private halfW: number = 0;
    private halfH: number = 0;

    private minX: number = 0;
    private maxX: number = 1000;
    private minY: number = 0;
    private maxY: number = 1000;

    private state: number = 0;
    private src: Vec2 = new Vec2(0, 0);
    private des: Vec2 = new Vec2(0, 0);
    private offset: Vec2 = new Vec2(0, 0);
    private time: number = 0;
    private duration: number = 0;

    private handleFinish!: Function | null | undefined;
    private handleTarget: any;

    public get x(): number {
        return this.root.position.x - this.offset.x;
    }

    public get y(): number {
        return this.root.position.y - this.offset.y;
    }

    public start() {
        TimerManager.inst.addUpdate(this);
    }

    public destroy() {
        TimerManager.inst.remove(this);
    }

    public setRoot(root: Node, width: number, height: number) {
        this._x = 0;
        this._y = 0;
        this.scale = 1;
        this.root = root;
        this.root.setScale(1, 1);
        this.root.setPosition(0, 0);
        this.setSize(width, height);
    }

    public setSize(width: number, height: number) {
        this.width = width;
        this.height = height;
        this.halfW = width * 0.5;
        this.halfH = height * 0.5;
        this.refreshRange();
    }

    public refreshRange() {
        let width = this.width * this.scale;
        let height = this.height * this.scale;
        let screen = UIRoot.GetMainTransform().contentSize;
        this.minX = 0.5 * (screen.width - width);
        this.maxX = 0.5 * (width - screen.width);
        this.minY = 0.5 * (screen.height - height);
        this.maxY = 0.5 * (height - screen.height);
    }

    public setOffset(x: number, y: number) {
        this.offset.x = x;
        this.offset.y = y;
    }

    public setPosition(x: number, y: number) {
        this._x = x + this.offset.x;
        this._y = y + this.offset.y;
        this.updatePosition();
    }

    public getPosition(): Vec2 {
        return new Vec2(this._x - this.offset.x, this._y - this.offset.y);
    }

    public setScale(scale: number) {
        this.scale = scale;
        this.root.setScale(scale, scale);
        this.refreshRange();
        this.updatePosition();
    }

    public getScale(): number {
        return this.scale;
    }


    private updatePosition() {
        let fx = -this._x * this.scale;
        let fy = -this._y * this.scale;
        fx = math.clamp(fx, this.minX, this.maxX);
        fy = math.clamp(fy, this.minY, this.maxY);
        this.root.setPosition(fx, fy);
        this._x = -fx / this.scale;
        this._y = -fy / this.scale;
    }


    public moveTo(x: number, y: number, speed: number, onFinish?: Function, target?: any) {
        this.src.x = this._x;
        this.src.y = this._y;
        this.des.x = x + this.offset.x;
        this.des.y = y + this.offset.y;
        this.time = 0;
        this.state = 1;
        this.duration = Vec2.distance(this.src, this.des) / speed;
        this.duration = Math.min(this.duration, 0.5);
        this.handleFinish = onFinish;
        this.handleTarget = target;
    }

    public update(dt: number) {
        if (this.state == 0) return;
        this.time += dt;
        if (this.time < this.duration) {
            let t = this.time / this.duration;
            this._x = math.lerp(this.src.x, this.des.x, t);
            this._y = math.lerp(this.src.y, this.des.y, t);
            this.updatePosition();
        }
        else {
            this._x = this.des.x;
            this._y = this.des.y;
            this.updatePosition();
            this.state = 0;
            if (this.handleFinish)
                this.handleFinish.call(this.handleTarget);
        }
    }

    public get isMoving(): boolean {
        return this.state == 1;
    }

}